// Go作者版权所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// +构建忽略

package main

import "strings"

// 笔记：
// -整数类型位于寄存器的低位。上部是垃圾。
// -布尔类型使用寄存器的低位字节。0=假，1=真。
// 上面的字节是垃圾。
// -*常量指令可能使用大于指令编码的常量。
// 在这种情况下，汇编程序扩展到多条指令并使用tmp
// 寄存器（R23）。

// 后缀对各种指令的位宽度进行编码。
// V（vlong）=64位
// WU（字）=32位无符号
// W（字）=32位
// H（半字）=16位
// HU=16位无符号
// B（字节）=8位
// BU=8位无符号
// F（浮点）=32位浮点
// D（双）=64位浮点

// 注：regalloc中未使用的寄存器不包括在此列表中，
// 所以regmask保持在int64内
// 手工编码时要小心。
var regNamesMIPS64 = []string{
	"R0", // 常数0
	"R1",
	"R2",
	"R3",
	"R4",
	"R5",
	"R6",
	"R7",
	"R8",
	"R9",
	"R10",
	"R11",
	"R12",
	"R13",
	"R14",
	"R15",
	"R16",
	"R17",
	"R18",
	"R19",
	"R20",
	"R21",
	"R22",
	// R23=regalloc中未使用REGTMP
	"R24",
	"R25",
	// R26由内核保留
	// R27由内核保留
	// R28=regalloc中未使用REGSB
	"SP",  // 又名R29
	"g",   // 又名R30
	"R31", // 又名REGLINK

	"F0",
	"F1",
	"F2",
	"F3",
	"F4",
	"F5",
	"F6",
	"F7",
	"F8",
	"F9",
	"F10",
	"F11",
	"F12",
	"F13",
	"F14",
	"F15",
	"F16",
	"F17",
	"F18",
	"F19",
	"F20",
	"F21",
	"F22",
	"F23",
	"F24",
	"F25",
	"F26",
	"F27",
	"F28",
	"F29",
	"F30",
	"F31",

	"HI", // 乘法高位
	"LO", // 乘法低位

	// 如果添加寄存器，请在运行时更新asyncPreempt。

	// 伪寄存器
	"SB",
}

func init() {
	// 将reg名称映射到reg整数。
	if len(regNamesMIPS64) > 64 {
		panic("too many registers")
	}
	num := map[string]int{}
	for i, name := range regNamesMIPS64 {
		num[name] = i
	}
	buildReg := func(s string) regMask {
		m := regMask(0)
		for _, r := range strings.Split(s, " ") {
			if n, ok := num[r]; ok {
				m |= regMask(1) << uint(n)
				continue
			}
			panic("register " + r + " not found")
		}
		return m
	}

	// 通用单个寄存器掩码
	var (
		gp         = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31")
		gpg        = gp | buildReg("g")
		gpsp       = gp | buildReg("SP")
		gpspg      = gpg | buildReg("SP")
		gpspsbg    = gpspg | buildReg("SB")
		fp         = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
		lo         = buildReg("LO")
		hi         = buildReg("HI")
		callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg（以及任何调用它的东西）可能会重击g
		r1         = buildReg("R1")
		r2         = buildReg("R2")
		r3         = buildReg("R3")
		r4         = buildReg("R4")
	)
	// 公共区域信息
	var (
		gp01     = regInfo{inputs: nil, outputs: []regMask{gp}}
		gp11     = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
		gp11sp   = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
		gp21     = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
		gp2hilo  = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
		gpload   = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
		gpstore  = regInfo{inputs: []regMask{gpspsbg, gpg}}
		gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
		gpxchg   = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
		gpcas    = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
		fp01     = regInfo{inputs: nil, outputs: []regMask{fp}}
		fp11     = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
		// fp1flags=regInfo{inputs:[]regMask{fp}
		// fpgp=regInfo{input:[]regMask{fp}，output:[]regMask{gp}
		// gpfp=regInfo{input:[]regMask{gp}，output:[]regMask{fp}
		fp21      = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
		fp2flags  = regInfo{inputs: []regMask{fp, fp}}
		fpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
		fpstore   = regInfo{inputs: []regMask{gpspsbg, fp}}
		readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
	)
	ops := []opData{
		// 二进制操作
		{name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true},                             // arg0+arg1
		{name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"},                           // arg0+生长素。生长素是32位的，在其他常数中也是如此。
		{name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"},                                                // arg0-arg1
		{name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"},                             // arg0-生长素
		{name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"},     // arg0*arg1，有符号，结果高，低
		{name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0*arg1，无符号，结果高，低
		{name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"},                        // arg0/arg1，已签名，结果hi=arg0%arg1，lo=arg0/arg1
		{name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"},                    // arg0/arg1，已签名，结果hi=arg0%arg1，lo=arg0/arg1

		{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0+arg1
		{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0+arg1
		{name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0-arg1
		{name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0-arg1
		{name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0*arg1
		{name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0*arg1
		{name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0/arg1
		{name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0/arg1

		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0和arg1
		{name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"},                // arg0&生长素
		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                  // arg0 |生长素
		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0^arg1
		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0^生长素
		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^（arg0 | arg1）
		{name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"},                // ^（arg0 |生长素）

		{name: "NEGV", argLength: 1, reg: gp11},                // -arg0
		{name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"},   // -arg0，32
		{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0，64
		{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt（arg0），浮点64
		{name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt（arg0），浮动32

		// 转移
		{name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"},                    // arg0<<arg1，移位量为mod 64
		{name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0<<生长素
		{name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"},                    // arg0>>arg1，无符号，移位量为mod 64
		{name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0>>生长素，未签名
		{name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"},                    // arg0>>arg1，已签名，移位量为mod 64
		{name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0>>生长素，已签名

		// 比较
		{name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 如果arg0>arg1（已签名），则为1，否则为0
		{name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"},   // 如果生长素>arg0（有符号），则为1，否则为0
		{name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 如果arg0>arg1（无符号），则为1，否则为0
		{name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 如果生长素>arg0（无符号），则为1，否则为0

		{name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // 如果arg0=arg1，则flags=true，浮动32
		{name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // 如果arg0=arg1，则flags=true，浮点64
		{name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // 如果arg0>=arg1，则flags=true，浮动32
		{name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // 如果arg0>=arg1，则flags=true，浮点64
		{name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // 如果arg0>arg1，则flags=true，浮动32
		{name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // 如果arg0>arg1，则flags=true，浮点64

		// 移动
		{name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true},    // 生长素
		{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // 生长素为64位浮点，转换为32位浮点
		{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // 生长素作为64位浮点

		{name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0+auxInt+aux（*gc.Sym），arg0=SP/SB

		{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // 从arg0+auxInt+aux加载。arg1=mem。
		{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // 从arg0+auxInt+aux加载。arg1=mem。
		{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // 从arg0+auxInt+aux加载。arg1=mem。
		{name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // 从arg0+auxInt+aux加载。arg1=mem。
		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // 从arg0+auxInt+aux加载。arg1=mem。
		{name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // 从arg0+auxInt+aux加载。arg1=mem。
		{name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},   // 从arg0+auxInt+aux加载。arg1=mem。
		{name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // 从arg0+auxInt+aux加载。arg1=mem。
		{name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // 从arg0+auxInt+aux加载。arg1=mem。

		{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将arg1的1字节存储到arg0+auxInt+aux。arg2=mem。
		{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将arg1的2个字节存储到arg0+auxInt+aux。arg2=mem。
		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将arg1的4个字节存储到arg0+auxInt+aux。arg2=mem。
		{name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将8字节的arg1存储到arg0+auxInt+aux。arg2=mem。
		{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将arg1的4个字节存储到arg0+auxInt+aux。arg2=mem。
		{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将8字节的arg1存储到arg0+auxInt+aux。arg2=mem。

		{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将0的1字节存储到arg0+auxInt+aux。arg1=mem。
		{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将2个字节的零存储到arg0+auxInt+aux。arg1=mem。
		{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将4个字节的零存储到arg0+auxInt+aux。arg1=mem。
		{name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 将8个字节的零存储到arg0+auxInt+aux。ar12=mem。

		// 转换
		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // 从arg0移动，从字节扩展符号
		{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // 从arg0移动，从字节扩展为无符号
		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // 从arg0开始移动，符号从一半延伸
		{name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // 从arg0开始移动，从一半开始无符号扩展
		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // 从arg0移动，从word扩展符号
		{name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // 从arg0移动，从word扩展为无符号
		{name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"},   // 从arg0移动

		{name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // 否，返回同一寄存器中的arg0

		{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32->float32
		{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32->float64
		{name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"},     // int64->float32
		{name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"},     // int64->float64
		{name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32->int32
		{name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // 浮点64->int32
		{name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32->int64
		{name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // 浮点64->int64
		{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // 浮动32->浮动64
		{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // 浮动64->浮动32

		// 函数调用
		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                               // 调用静态函数aux。（*obj.LSym）。arg0=mem，auxint=argsize，返回mem
		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // 通过闭包调用函数。arg0=codeptr，arg1=closure，arg2=mem，auxint=argsize，返回mem
		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                         // 通过指针调用fn。arg0=codeptr，arg1=mem，auxint=argsize，返回mem

		// 达夫零
		// arg0=内存地址为零
		// arg1=mem
		// auxint=偏移到duffzero代码中以开始执行
		// 返回mem
		// R1 aka mips.REGRT1因副作用而改变
		{
			name:      "DUFFZERO",
			aux:       "Int64",
			argLength: 2,
			reg: regInfo{
				inputs:   []regMask{gp},
				clobbers: buildReg("R1 R31"),
			},
			faultOnNilArg0: true,
		},

		// 复印件
		// arg0=dst内存地址（在R2中，因副作用而更改）
		// arg1=src内存地址（在R1中，因副作用而更改）
		// arg2=mem
		// auxint=要开始执行的duffcopy代码的偏移量
		// 返回mem
		{
			name:      "DUFFCOPY",
			aux:       "Int64",
			argLength: 3,
			reg: regInfo{
				inputs:   []regMask{buildReg("R2"), buildReg("R1")},
				clobbers: buildReg("R1 R2 R31"),
			},
			faultOnNilArg0: true,
			faultOnNilArg1: true,
		},

		// 大的或未对齐的归零
		// arg0=内存地址为零（在R1中，因副作用而更改）
		// arg1=最后一个元素的地址为零
		// arg2=mem
		// 生长素=排列
		// 返回mem
		// 低于8美元，R1
		// MOVV R0，8（R1）
		// ADDV$8，R1
		// BNE Rarg1，R1，-2（PC）
		{
			name:      "LoweredZero",
			aux:       "Int64",
			argLength: 3,
			reg: regInfo{
				inputs:   []regMask{buildReg("R1"), gp},
				clobbers: buildReg("R1"),
			},
			clobberFlags:   true,
			faultOnNilArg0: true,
		},

		// 大的或未对齐的移动
		// arg0=dst内存地址（在R2中，因副作用而更改）
		// arg1=src内存地址（在R1中，因副作用而更改）
		// arg2=src最后一个元素的地址
		// arg3=mem
		// 生长素=排列
		// 返回mem
		// 低于8美元，R1
		// MOV8（R1），Rtmp
		// MOVV-Rtmp（R2）
		// ADDV$8，R1
		// 附加价值8美元，R2
		// BNE Rarg2，R1，-4（PC）
		{
			name:      "LoweredMove",
			aux:       "Int64",
			argLength: 4,
			reg: regInfo{
				inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
				clobbers: buildReg("R1 R2"),
			},
			clobberFlags:   true,
			faultOnNilArg0: true,
			faultOnNilArg1: true,
		},

		// 原子负荷。
		// 从arg0加载。arg1=mem。
		// 返回<value，memory>，以便可以与其他加载一起正确排序。
		{name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
		{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true},

		// 原子仓库。
		// 将arg1存储到arg0。arg2=mem。返回内存。
		{name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
		// 将零存储到arg0。arg1=mem。返回内存。
		{name: "LoweredAtomicStorezero32", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
		{name: "LoweredAtomicStorezero64", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},

		// 原子交换。
		// 将arg1存储到arg0。arg2=mem。返回<old content of*arg0，memory>。
		// 同步
		// LL（Rarg0），路由器
		// MOVV Rarg1，Rtmp
		// SC Rtmp（Rarg0）
		// BEQ Rtmp，-3（件）
		// 同步
		{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
		{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},

		// 原子加法。
		// *arg0+=arg1。arg2=mem。返回<新的*arg0内容，内存>。
		// 同步
		// LL（Rarg0），路由器
		// 地址Rarg1，路由，Rtmp
		// SC Rtmp（Rarg0）
		// BEQ Rtmp，-3（件）
		// 同步
		// 地址：Rarg1，路由器
		{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
		{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
		// *arg0+=生长素。arg1=mem。返回<新的*arg0内容，内存>。生长素是32位的。
		{name: "LoweredAtomicAddconst32", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
		{name: "LoweredAtomicAddconst64", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int64", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},

		// 原子比较和交换。
		// arg0=指针，arg1=旧值，arg2=新值，arg3=内存。
		// 如果*arg0==arg1{
		// *arg0=arg2
		// 返回（真，内存）
		// }否则{
		// 返回（假，内存）
		// }
		// 同步
		// MOVV$0，溃败
		// LL（Rarg0），Rtmp
		// BNE Rtmp，Rarg1，4（件）
		// movrarg2，Rout
		// SC路由（Rarg0）
		// BEQ线路-4（PC）
		// 同步
		{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
		{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},

		// 伪操作
		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // 如果arg0为零，则出现恐慌。arg1=mem。

		{name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool，如果FP标志为true，则为true
		{name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool，如果FP标志为false，则为true

		// 调度器确保LoweredGetClosurePtr仅在入口块中发生，
		// 并将其排序到块的最开始，以防止其他
		// R22（mips.REGCTXT，闭包指针）的使用
		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},

		// LoweredGetCallerSP返回当前函数调用方的SP。
		{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},

		// LoweredGetCallerPC计算其“调用者”将返回的PC。
		// 也就是说，如果f调用g“calls”getcallerpc，
		// 结果应为g将返回到的f内的PC。
		// 有关更详细的讨论，请参阅runtime/stubs.go。
		{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},

		// LoweredWB调用runtime.gcWriteBarrier。arg0=destptr，arg1=srcptr，arg2=mem，aux=runtime.gcWriteBarrier
		// 如有必要，它会保存所有GP寄存器，
		// 但击倒了R31（LR），因为这是一个电话
		// 和R23(REGTMP)。
		{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},

		// 这些函数有三个，因此它们可以有三个不同的寄存器输入。
		// 当我们检查0<=c<=cap（A），然后检查0<=b<=c（b），然后检查0<=A<=b（c），我们需要
		// 要匹配的默认寄存器，因此我们不需要不必要地复制寄存器。
		{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem", call: true}, // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。
		{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem", call: true}, // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。
		{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem", call: true}, // arg0=idx，arg1=len，arg2=mem，返回内存。AuxInt包含报告代码（参见genericOps.go中的PanicBounds）。
	}

	blocks := []blockData{
		{name: "EQ", controls: 1},
		{name: "NE", controls: 1},
		{name: "LTZ", controls: 1}, // < 0
		{name: "LEZ", controls: 1}, // <= 0
		{name: "GTZ", controls: 1}, // > 0
		{name: "GEZ", controls: 1}, // >= 0
		{name: "FPT", controls: 1}, // FP标志为真
		{name: "FPF", controls: 1}, // FP标志为false
	}

	archs = append(archs, arch{
		name:            "MIPS64",
		pkg:             "cmd/internal/obj/mips",
		genfile:         "../../mips64/ssa.go",
		ops:             ops,
		blocks:          blocks,
		regnames:        regNamesMIPS64,
		gpregmask:       gp,
		fpregmask:       fp,
		specialregmask:  hi | lo,
		framepointerreg: -1, // 不用
		linkreg:         int8(num["R31"]),
	})
}
